A data type in programming languages is an attribute of data which imparts information about what kind of data it is. Constraints, such as what types of values the piece of data can take and what operations can be performed upon it, can also be established by assigning a data type to the data. A type system associates one or more data types with each program value in a program. By examining what the instructions in the program do to the value of the data, a type system attempts to prevent “type errors”. For example, a particular programming language may consider assigning a string value to a variable of integer type to be a type error and will give an error message to the user who tries to do so. A type system also attempts to prevent illegal operations on data. For example, some programming languages consider adding a string and an integer together to be an illegal operation and will give an error message to the user who tries to do so. Type checking can occur either at compile time (a static check or static type checking) or at runtime (a dynamic check or dynamic type checking). If a language applies its typing rules vigorously, (for example, only allowing automatic type conversions which do not lose information), it is called a strongly-typed language. If a language is relatively less restrictive, it is called weakly typed.
A programming language is said to use static typing when type checking is performed during compile time. In static typing, types are associated with variables. Statically typed languages include Ada, C, C++, C#, Java, Fortran, Haskell, ML, Pascal and Scala. Static typing allows many errors to be caught early in the development cycle. Because static type checkers evaluate type information during compilation, and lack type information that is only available at runtime, static type checkers are conservative. That is, even if a particular execution of a program would run correctly, the program will be rejected by a static type checker if the conditions evaluated do not hold for all possible executions of the program. Because static type checkers evaluate the type information that can be determined at compile time and verify that the checked conditions hold for all possible executions of the program, there is no need to repeat static type checks every time the program is executed.
A programming language is said to be dynamically typed when most of the type checking is performed at runtime. In dynamic typing types are associated with values resulting from execution of the program. Dynamically typed languages include Clojure, Groovy, JavaScript, Lisp, Objective-C, PHP, Prolog, Python, Ruby, and Smalltalk. Dynamic typing is less rigid than static typing but can result in a greater potential for execution errors (e.g., an error results because a value for a variable has an unallowed type). Dynamically typed language systems typically make fewer compile time checks on the source code. Runtime checks potentially can be more sophisticated because they can use dynamic (runtime) information in addition to information that was present during compilation and is still available at runtime. Runtime checks assert that conditions hold in a particular execution of the program and are repeated for each execution of the program.
Binding also selects which actual operation to use when a syntactic operation is applied in source code. Binding can occur either at compile time, in which case it is called “static binding”, or can occur dynamically at runtime, which is called “dynamic binding”. Dynamic binding allows the postponement of the resolving of undefined variables until a program is run. Dynamic binding is fundamentally different from static binding because its result—the meaning assigned to an operation, for example—depends on the runtime types of the actual values it operates on instead of on the compile time types of the variables in the source code. Typically, statically typed programming languages perform static binding and dynamically typed programming languages perform dynamic binding. Moreover, typically, binding of a particular operation is either fully static (binding occurs at compile time based on the compile time types of the variables in the source code) or is fully dynamic (binding occurs at runtime based on the runtime types of the runtime values resulting from computations).